<template>
    <view class="da-tree" :style="{ '--theme-color': themeColor }">
        <scroll-view class="da-tree-scroll" :scroll-y="true" :scroll-x="false">
            <view
                class="da-tree-item"
                :class="{ 'is-show': item.show }"
                :style="{ paddingLeft: item.level * indent + 'rpx' }"
                v-for="item in datalist"
                :key="item.key"
            >
                <view
                    v-if="item.showArrow && !filterValue"
                    class="da-tree-item__icon"
                    @click="handleExpandedChange(item)"
                >
                    <view
                        :class="['da-tree-item__icon--arr', 'is-loading']"
                        v-if="loadLoading && item.loading"
                    ></view>
                    <view
                        :class="[
                            'da-tree-item__icon--arr',
                            'is-expand',
                            { 'is-right': !item.expand }
                        ]"
                        v-else
                    ></view>
                </view>
                <view v-else class="da-tree-item__icon"></view>
                <view
                    class="da-tree-item__checkbox"
                    :class="[
                        `da-tree-item__checkbox--${checkboxPlacement}`,
                        { 'is--disabled': item.disabled }
                    ]"
                    v-if="showCheckbox"
                    @click="handleCheckChange(item)"
                >
                    <view
                        class="da-tree-item__checkbox--icon da-tree-checkbox-checked"
                        v-if="item.checkedStatus === isCheckedStatus"
                    ></view>
                    <view
                        class="da-tree-item__checkbox--icon da-tree-checkbox-indeterminate"
                        v-else-if="item.checkedStatus === halfCheckedStatus"
                    ></view>
                    <view
                        class="da-tree-item__checkbox--icon da-tree-checkbox-outline"
                        v-else
                    ></view>
                </view>
                <view
                    class="da-tree-item__checkbox"
                    :class="[
                        `da-tree-item__checkbox--${checkboxPlacement}`,
                        { 'is--disabled': item.disabled }
                    ]"
                    v-if="!showCheckbox && showRadioIcon"
                    @click="handleRadioChange(item)"
                >
                    <view
                        class="da-tree-item__checkbox--icon da-tree-radio-checked"
                        v-if="item.checkedStatus === isCheckedStatus"
                    ></view>
                    <view
                        class="da-tree-item__checkbox--icon da-tree-radio-indeterminate"
                        v-else-if="item.checkedStatus === halfCheckedStatus"
                    ></view>
                    <view
                        class="da-tree-item__checkbox--icon da-tree-radio-outline"
                        v-else
                    ></view>
                </view>
                <view
                    class="da-tree-item__label"
                    :class="'da-tree-item__label--' + item.checkedStatus"
                    @click="handleLabelClick(item)"
                    >{{ item.label }}
                    <text
                        class="da-tree-item__label--append"
                        v-if="item.append"
                        >{{ item.append }}</text
                    ></view
                >
            </view>
        </scroll-view>
    </view>
</template>

<script>
import { defineComponent, ref, unref, watch } from 'vue'

import {
    unCheckedStatus,
    halfCheckedStatus,
    isCheckedStatus,
    deepClone,
    getAllNodeKeys,
    getAllNodes,
    logError,
    isArray,
    isString,
    isNumber,
    isFunction
} from './utils'
import basicProps from './props'

export default defineComponent({
    name: 'DaTree',
    props: basicProps,
    emits: ['change', 'expand'],
    setup(props, { emit }) {
        /** 原始的树数据 */
        const dataRef = ref([])
        /** 处理后的一维树项数据 */
        const datalist = ref([])
        /** 处理后的以key为键值的树项数据 */
        const datamap = ref({})
        /** 默认的展开数据 */
        const expandedKeys = ref([])
        /** 默认的已选数据 */
        const checkedKeys = ref(null)
        /** 加载状态 */
        const loadLoading = ref(false)
        let fieldMap = {
            value: 'value',
            label: 'label',
            children: 'children',
            disabled: 'disabled',
            append: 'append',
            leaf: 'leaf',
            sort: 'sort'
        }

        /**
         * 初始化数据结构
         */
        function initData() {
            fieldMap = {
                value:
                    props.field?.key ||
                    props.field?.value ||
                    props.valueField ||
                    'value',
                label: props.field?.label || props.labelField || 'label',
                children:
                    props.field?.children || props.childrenField || 'children',
                disabled:
                    props.field?.disabled || props.disabledField || 'disabled',
                append: props.field?.append || props.appendField || 'append',
                leaf: props.field?.leaf || props.leafField || 'leaf',
                sort: props.field?.sort || props.sortField || 'sort'
            }

            const data = deepClone(dataRef.value)
            datalist.value = []
            datamap.value = {}

            // clean tree
            handleTreeData(data)
            // flat tree
            datalist.value = checkInitData(datalist.value)
            // console.log('init datalist', datalist.value)
            // console.log('init datamap', datamap.value)
        }

        /**
         * 转换为节点数据
         * @param data
         * @param parent
         * @param level
         */
        function handleTreeData(
            data = [],
            parent = null,
            level = 0,
            insertIndex = -1
        ) {
            return data.reduce((prev, cur, index) => {
                const key = cur[fieldMap.value]
                const children = cur[fieldMap.children] || null
                const newItem = createNewItem(cur, index, parent, level)
                if (insertIndex > -1) {
                    // 插入子项尾部
                    const index =
                        (parent.childrenKeys?.length || 0) + insertIndex + 1
                    if (!parent?.childrenKeys?.includes(key)) {
                        datamap.value[key] = newItem
                        datalist.value.splice(index, 0, newItem)
                        parent.children.push(newItem)
                        if (newItem.parentKeys?.length) {
                            newItem.parentKeys.forEach((k) => {
                                datamap.value[k].childrenKeys = [
                                    ...datamap.value[k].childrenKeys,
                                    newItem.key
                                ]
                            })
                        }
                    }
                } else {
                    datamap.value[key] = newItem
                    datalist.value.push(newItem)
                }

                const hasChildren = children && children.length > 0
                if (hasChildren) {
                    const childrenData = handleTreeData(
                        children,
                        newItem,
                        level + 1
                    )
                    // childrenData.sort((a, b) => a.sort - b.sort)
                    newItem.children = childrenData
                    const childrenKeys = childrenData.reduce((p, k) => {
                        const keys = k.childrenKeys
                        p.push(...keys, k.key)
                        return p
                    }, [])
                    newItem.childrenKeys = childrenKeys
                }
                prev.push(newItem)
                return prev
            }, [])
        }

        /**
         * 创建节点
         * @param item
         * @param index
         * @param parent
         * @param level
         */
        function createNewItem(item, index, parent, level) {
            const key = item[fieldMap.value]
            const label = item[fieldMap.label]
            const sort = item[fieldMap.sort] || 0
            const children = item[fieldMap.children] || null
            const append = item[fieldMap.append] || null
            let disabled = item[fieldMap.disabled] || false
            // 优先继承父级禁用属性
            disabled = parent?.disabled || disabled
            let isLeaf = isFunction(props.isLeafFn)
                ? props.isLeafFn(item)
                : item[fieldMap.leaf] || false
            // const hasChildren = children && children.length > 0
            const isEmptyChildren = children && children.length === 0
            let showArrow = true
            // let isLeaf = !hasChildren
            let expand = props.defaultExpandAll || false
            // 是否异步加载模式
            const isLoadMode = props.loadMode && isFunction(props.loadApi)

            if (!children) {
                expand = false
                if (isLoadMode) {
                    showArrow = true
                } else {
                    isLeaf = true
                    showArrow = false
                }
            }

            if (isEmptyChildren) {
                expand = false
                if (isLoadMode) {
                    showArrow = true
                } else {
                    isLeaf = true
                    showArrow = false
                }
            }

            if (isLeaf) {
                showArrow = false
                expand = false
            } else {
                showArrow = true
            }

            // onlyRadioLeaf 单选只能选择末级节点
            if (!props.showCheckbox) {
                if (props.onlyRadioLeaf) {
                    if (!isLeaf) {
                        disabled = true
                    } else {
                        // 仍旧继承父类原始禁用状态
                        disabled = parent?.originItem?.disabled || false
                    }
                }
            }

            if (disabled) {
                if (isLeaf || !children || isEmptyChildren) {
                    expand = false
                    showArrow = false
                }
            }

            const parentKey = parent ? parent.key : null
            const show = props.defaultExpandAll || level === 0

            const newItem = {
                key,
                parentKey,
                label,
                append,
                isLeaf,
                showArrow,
                level,
                expand,
                show,
                sort,
                disabled,
                loaded: false,
                loading: false,
                indexs: [index],
                checkedStatus: unCheckedStatus,
                parentKeys: [],
                childrenKeys: [],
                children: [],
                originItem: item
            }

            if (parent) {
                newItem.parentKeys = [parent.key, ...parent.parentKeys]
                newItem.indexs = [...parent.indexs, index]
            }

            return newItem
        }

        /**
         * 处理初始化内容
         * @param list
         */
        function checkInitData(list) {
            let checkedKeyList = null
            let expandedKeyList = []
            if (props.showCheckbox) {
                checkedKeyList = [...new Set(checkedKeys.value || [])]
                expandedKeyList = props.expandChecked
                    ? [
                          ...(checkedKeys.value || []),
                          ...(expandedKeys.value || [])
                      ]
                    : expandedKeys.value
            } else {
                checkedKeyList = checkedKeys.value || null
                expandedKeyList =
                    props.expandChecked && checkedKeys.value
                        ? [checkedKeys.value, ...(expandedKeys.value || [])]
                        : expandedKeys.value
            }

            handleCheckState(list, checkedKeyList, true)

            // 处理初始展开
            expandedKeyList = [...new Set(expandedKeyList)]
            if (!props.defaultExpandAll) {
                handleExpandState(list, expandedKeyList, true)
            }

            list.sort((a, b) => {
                if (a.sort === 0 && b.sort === 0) {
                    return 0
                }

                if (a.parentKey === b.parentKey) {
                    if (a.sort - b.sort > 0) {
                        return 1
                    } else {
                        return -1
                    }
                }

                return 0
            })

            return list
        }

        /**
         * 处理选中
         * @param list
         * @param checkedKeyList
         */
        function handleCheckState(list, checkedKeyList, checked = true) {
            // 多选
            if (props.showCheckbox) {
                if (checkedKeyList?.length) {
                    checkedKeyList.forEach((k) => {
                        const item = datamap.value[k]
                        if (item) {
                            checkTheChecked(item, checked)
                        }
                    })
                }

                return
            }

            // 单选
            for (let i = 0; i < list.length; i++) {
                const item = list[i]
                if (item.key === checkedKeyList) {
                    checkTheRadio(item, checked)
                    break
                }
            }
        }

        /**
         * 校验多选节点
         * @param item
         * @param checked
         */
        function checkTheChecked(item, checked = true) {
            const { childrenKeys, parentKeys, disabled = false } = item
            if (!props.checkedDisabled && disabled) return

            // 当前
            item.checkedStatus = checked ? isCheckedStatus : unCheckedStatus

            if (!props.checkStrictly) {
                // 子类
                childrenKeys.forEach((k) => {
                    const childrenItem = unref(datamap)[k]
                    childrenItem.checkedStatus =
                        !props.checkedDisabled && childrenItem.disabled
                            ? childrenItem.checkedStatus
                            : item.checkedStatus
                })

                // 父类
                parentKeys.forEach((k) => {
                    const parentItem = datamap.value[k]
                    parentItem.checkedStatus =
                        getParentCheckedStatus(parentItem)
                })
            }
        }

        /**
         * 校验单选节点
         * @param item
         */
        function checkTheRadio(item, checked) {
            const { parentKeys, isLeaf, disabled = false } = item
            if (!props.checkedDisabled && disabled) return

            // 限制末节点选中，但当前非末节点
            if (props.onlyRadioLeaf && !isLeaf) {
                logError(`限制了末节点选中，当前[${item.label}]非末节点`)
                return
            }

            if (datalist.value?.length) {
                datalist.value.forEach((k) => {
                    k.checkedStatus = unCheckedStatus
                })
            }

            parentKeys.forEach((k) => {
                const parentItem = datamap.value[k]
                parentItem.checkedStatus = checked
                    ? getParentCheckedStatus(parentItem)
                    : unCheckedStatus
            })

            // 当前
            item.checkedStatus = checked ? isCheckedStatus : unCheckedStatus
        }

        /**
         * 处理父节点展开
         * @param item
         * @param expand
         */
        // function handleExpandParentNode(item, expand = true) {
        //   if (!expand) return

        //   if (item?.parentKeys?.length) {
        //     item.parentKeys.forEach(pk => {
        //       if (!datamap.value[pk].expand) {
        //         datamap.value[pk].expand = true
        //       }
        //     })
        //   }
        // }

        /**
         * 处理节点展开
         * @param list
         * @param expandedKeyList
         * @param expand
         */
        function handleExpandState(list, expandedKeyList, expand = true) {
            // 收起
            if (expand === false) {
                for (let i = 0; i < list.length; i++) {
                    const item = list[i]
                    if (expandedKeyList?.includes(item.key)) {
                        item.expand = false
                        if (item.childrenKeys?.length) {
                            item.childrenKeys.forEach((ck) => {
                                datamap.value[ck].expand = false
                                datamap.value[ck].show = false
                            })
                        }
                    }
                }
                return
            }
            // 展开
            for (let i = 0; i < list.length; i++) {
                const item = list[i]
                // 处理展开
                if (expandedKeyList?.includes(item.key)) {
                    // 父子
                    item.expand = true
                    if (item.children?.length) {
                        item.children.forEach((k) => {
                            const kItem = unref(datamap)[k.key]
                            kItem.show = true
                        })
                    }

                    // 族系
                    if (item.parentKeys?.length) {
                        item.parentKeys.forEach((k) => {
                            const kItem = unref(datamap)[k]
                            kItem.expand = true
                            if (kItem.children?.length) {
                                kItem.children.forEach((k) => {
                                    const skItem = unref(datamap)[k.key]
                                    skItem.show = true
                                })
                            }
                        })
                    }
                }
            }
        }

        /**
         * 点击选框
         * @param item
         */
        function handleCheckChange(item) {
            const {
                childrenKeys,
                parentKeys,
                checkedStatus,
                isLeaf,
                disabled = false
            } = item
            if (!props.showCheckbox) return
            if (disabled) return

            // 当前
            item.checkedStatus =
                checkedStatus === isCheckedStatus
                    ? unCheckedStatus
                    : isCheckedStatus

            // 子类
            if (!props.checkStrictly) {
                if (props.expandChecked) {
                    item.show = true
                    item.expand = childrenKeys?.length > 0 || isLeaf
                }

                childrenKeys.forEach((k) => {
                    const childrenItem = unref(datamap)[k]
                    childrenItem.checkedStatus = childrenItem.disabled
                        ? childrenItem.checkedStatus
                        : item.checkedStatus

                    if (props.expandChecked) {
                        childrenItem.show = true
                        childrenItem.expand =
                            childrenItem?.childrenKeys?.length > 0 ||
                            childrenItem.isLeaf
                    }
                })
            } else {
                if (props.expandChecked) {
                    logError(
                        `多选时，当 checkStrictly 为 true 时，不支持选择自动展开子节点属性(expandChecked)`
                    )
                }
            }

            // 父类
            if (!props.checkStrictly) {
                parentKeys.forEach((k) => {
                    const parentItem = datamap.value[k]
                    parentItem.checkedStatus =
                        getParentCheckedStatus(parentItem)
                })
            }

            const hasCheckedKeys = []
            for (let i = 0; i < datalist.value.length; i++) {
                const k = datalist.value[i]
                if (k.checkedStatus === isCheckedStatus) {
                    if ((props.packDisabledkey && k.disabled) || !k.disabled) {
                        hasCheckedKeys.push(k.key)
                    }
                }
            }

            checkedKeys.value = [...hasCheckedKeys]

            emit('change', hasCheckedKeys, item)
        }

        /**
         * 点击单选
         * @param item
         */
        function handleRadioChange(item) {
            const {
                parentKeys,
                checkedStatus,
                key,
                disabled = false,
                isLeaf
            } = item
            if (props.showCheckbox) return
            if (props.onlyRadioLeaf && !isLeaf) handleExpandedChange(item)

            if (disabled) return

            // 重置所有选择
            if (datalist.value?.length) {
                for (let i = 0; i < datalist.value.length; i++) {
                    const k = datalist.value[i]
                    k.checkedStatus = unCheckedStatus
                }
            }

            parentKeys.forEach((k) => {
                const parentItem = datamap.value[k]
                parentItem.checkedStatus = getParentCheckedStatus(parentItem)
            })

            // 当前
            item.checkedStatus =
                checkedStatus === isCheckedStatus
                    ? unCheckedStatus
                    : isCheckedStatus

            checkedKeys.value = key
            emit('change', key, item)
        }

        /**
         * 点击标签
         */
        function handleLabelClick(item) {
            if (props.showCheckbox) {
                handleCheckChange(item)
            } else {
                handleRadioChange(item)
            }
        }

        /**
         * 点击展开收起
         * @param item
         */
        async function handleExpandedChange(item) {
            if (props.filterValue) return

            const { expand, loading = false, disabled } = item
            if (loadLoading.value && loading) return

            checkExpandedChange(item)

            // 异步
            item.expand = !expand

            let currentItem = null
            if (!disabled) {
                if (
                    !props.showCheckbox &&
                    props.onlyRadioLeaf &&
                    props.loadMode
                ) {
                    logError(
                        `单选时，当 onlyRadioLeaf 为 true 时不支持动态数据`
                    )
                } else {
                    currentItem = await loadExpandNode(item)
                }
            }

            emit('expand', !expand, currentItem || item || null)
        }

        /**
         * 检查展开状态
         * @param item
         */
        function checkExpandedChange(item) {
            const { expand, childrenKeys, children = null } = item

            if (expand) {
                if (childrenKeys?.length) {
                    childrenKeys.forEach((k) => {
                        if (unref(datamap)[k]) {
                            unref(datamap)[k].show = false
                            unref(datamap)[k].expand = false
                        }
                    })
                }
            } else {
                if (children?.length) {
                    const childrenKeys = children.map((k) => k.key)
                    childrenKeys.forEach((k) => {
                        if (unref(datamap)[k]) {
                            unref(datamap)[k].show = true
                        }
                    })
                }
            }
        }

        /**
         * 加载异步数据
         * @param item
         */
        async function loadExpandNode(item) {
            const { expand, key, loaded, children } = item
            if (children?.length && !props.alwaysFirstLoad) {
                return item
            }

            if (expand && props.loadMode && !loaded) {
                if (isFunction(props.loadApi)) {
                    expandedKeys.value.push(key)
                    loadLoading.value = true
                    item.loading = true

                    const currentNode = deepClone(item)
                    const apiRes = await props.loadApi(currentNode)

                    // 新增子项
                    let newChildren = [
                        ...(item.originItem?.children || []),
                        ...(apiRes || [])
                    ]
                    const newChildrenObj = {}
                    newChildren = newChildren.reduce((total, next) => {
                        newChildrenObj[next[fieldMap.value]]
                            ? ''
                            : (newChildrenObj[next[fieldMap.value]] =
                                  true && total.push(next))
                        return total
                    }, [])

                    item.originItem.children = newChildren || null
                    if (apiRes?.length) {
                        const insertIndex = datalist.value.findIndex(
                            (k) => k.key === item.key
                        )
                        handleTreeData(
                            apiRes,
                            item,
                            item.level + 1,
                            insertIndex
                        )
                        datalist.value = checkInitData(datalist.value)
                    } else {
                        // 加载后无数据就移除展开图标
                        item.expand = false
                        item.isLeaf = true
                        item.showArrow = false
                    }

                    loadLoading.value = false
                    item.loading = false
                    item.loaded = true
                }
            } else {
                const eki = expandedKeys.value.findIndex((k) => k === key)
                if (eki >= 0) {
                    expandedKeys.value.splice(eki, 1)
                }
            }

            return item
        }

        /**
         * 获取父类的选中状态
         * @param item
         */
        function getParentCheckedStatus(item) {
            if (!item) {
                return unCheckedStatus
            }

            if (!props.checkedDisabled && item.disabled) {
                return item.checkedStatus || unCheckedStatus
            }

            // 单选时，父类永远为半选
            if (!props.showCheckbox) {
                return halfCheckedStatus
            }

            const { children } = item
            // 子类全选中
            const childrenCheckedAll = children.every(
                (k) => k.checkedStatus === isCheckedStatus
            )
            if (childrenCheckedAll) {
                return isCheckedStatus
            }

            // 子类全不选中
            const childrenUncheckedAll = children.every(
                (k) => k.checkedStatus === unCheckedStatus
            )
            if (childrenUncheckedAll) {
                return unCheckedStatus
            }

            return halfCheckedStatus
        }

        function filterData() {
            if (props.filterValue === '') {
                datalist.value.forEach((k) => {
                    k.show = true
                })
                return
            }

            datalist.value.forEach((k) => {
                if (k.label.indexOf(props.filterValue) > -1) {
                    k.show = true
                    k.parentKeys.forEach((k) => {
                        datamap.value[k].show = true
                    })
                } else {
                    k.show = false
                }
            })

            datalist.value.forEach((k) => {
                if (k.show) {
                    k.parentKeys.forEach((k) => {
                        datamap.value[k].show = true
                    })
                }
            })
        }

        /**
         * 返回已选的 key
         */
        const getCheckedKeys = () =>
            getAllNodeKeys(
                datalist.value,
                'checkedStatus',
                isCheckedStatus,
                props.packDisabledkey
            )
        /**
         * 根据key设置已选
         * @param keys 单选时为数字或者字符串，多选时为数组
         * @param checked 多选时为key的数组，单选时为key
         */
        function setCheckedKeys(keys, checked = true) {
            // 多选
            if (props.showCheckbox) {
                if (!isArray(keys)) {
                    logError(
                        `setCheckedKeys 第一个参数非数组，传入的是[${keys}]`
                    )
                    return
                }

                const list = datalist.value

                // 取消选择
                if (checked === false) {
                    let newCheckedKeys = []
                    for (let i = 0; i < checkedKeys.value.length; i++) {
                        const ck = checkedKeys.value[i]
                        if (!keys.includes(ck)) {
                            newCheckedKeys.push(ck)
                        }
                    }
                    newCheckedKeys = [...new Set(newCheckedKeys)]
                    checkedKeys.value = newCheckedKeys
                    handleCheckState(list, keys, false)

                    return
                }

                // 选择
                const newCheckedKeys = [...checkedKeys.value, ...keys]
                checkedKeys.value = [...new Set(newCheckedKeys)]
                handleCheckState(list, checkedKeys.value, true)

                if (props.expandChecked && checked) {
                    expandedKeys.value = [
                        ...new Set([
                            ...(checkedKeys.value || []),
                            ...(keys || [])
                        ])
                    ]
                    handleExpandState(list, keys, true)
                }
                return
            }

            // 单选
            // 如果为数组则拿第一个
            if (isArray(keys)) {
                keys = keys[0]
            }

            if (!isString(keys) && !isNumber(keys)) {
                logError(
                    'setCheckedKeys 第一个参数字符串或数字，传入的是==>',
                    keys
                )
                return
            }

            const list = datalist.value
            checkedKeys.value = checked ? keys : null

            if (props.expandChecked && checked) {
                handleExpandState(list, [keys], true)
            }

            handleCheckState(list, keys, !!checked)
        }
        /**
         * 返回半选的 key
         */
        const getHalfCheckedKeys = () =>
            getAllNodeKeys(
                datalist.value,
                'checkedStatus',
                halfCheckedStatus,
                props.packDisabledkey
            )
        /**
         * 返回未选的 key
         */
        const getUncheckedKeys = () =>
            getAllNodeKeys(
                datalist.value,
                'checkedStatus',
                unCheckedStatus,
                props.packDisabledkey
            )
        /**
         * 返回已展开的 key
         */
        const getExpandedKeys = () =>
            getAllNodeKeys(datalist.value, 'expand', true)
        /**
         * 返回未展开的 key
         */
        const getUnexpandedKeys = () =>
            getAllNodeKeys(datalist.value, 'expand', false)
        /**
         * 根据key展开/收起
         *
         * @param keys 数组，或字符串 all
         * @param expand true为展开/false为收起
         */
        function setExpandedKeys(keys, expand = true) {
            if (!Array.isArray(keys) && keys !== 'all') {
                logError('setExpandedKeys 第一个参数非数组，传入的是===>', keys)
                return
            }

            const list = datalist.value

            // 展开/收起全部
            if (keys === 'all') {
                list.forEach((k) => {
                    k.expand = expand
                    if (k.level > 0) {
                        k.show = expand
                    }
                })
                return
            }

            // 收起
            if (expand === false) {
                const newExpandedKeys = []
                for (let i = 0; i < expandedKeys.value.length; i++) {
                    const ek = expandedKeys.value[i]
                    if (!keys.includes(ek)) {
                        newExpandedKeys.push(ek)
                    }
                }
                expandedKeys.value = [...new Set(newExpandedKeys)]
                handleExpandState(list, keys, false)

                return
            }

            // 展开
            const newExpandedKeys = []
            for (let i = 0; i < list.length; i++) {
                if (keys.includes(list[i].key)) {
                    newExpandedKeys.push(list[i].key)
                }
            }
            expandedKeys.value = [...new Set(newExpandedKeys)]
            handleExpandState(list, newExpandedKeys, true)
        }
        /**
         * 返回已选的节点
         */
        const getCheckedNodes = () =>
            getAllNodes(
                datalist.value,
                'checkedStatus',
                isCheckedStatus,
                props.packDisabledkey
            )
        /**
         * 返回半选的节点
         */
        const getHalfCheckedNodes = () =>
            getAllNodes(
                datalist.value,
                'checkedStatus',
                halfCheckedStatus,
                props.packDisabledkey
            )
        /**
         * 返回未选的节点
         */
        const getUncheckedNodes = () =>
            getAllNodes(
                datalist.value,
                'checkedStatus',
                unCheckedStatus,
                props.packDisabledkey
            )
        /**
         * 返回已展开的节点
         */
        const getExpandedNodes = () =>
            getAllNodes(datalist.value, 'expand', true)
        /**
         * 返回未展开的节点
         */
        const getUnexpandedNodes = () =>
            getAllNodes(datalist.value, 'expand', false)

        watch(
            () => props.defaultExpandedKeys,
            (v) => {
                if (v?.length) {
                    expandedKeys.value = v
                } else {
                    expandedKeys.value = []
                }

                // if (v) checkInitData(datalist.value)
            },
            { immediate: true }
        )

        watch(
            () => props.defaultCheckedKeys,
            (v) => {
                if (props.showCheckbox) {
                    if (v?.length) {
                        checkedKeys.value = v
                    } else {
                        checkedKeys.value = []
                    }
                } else {
                    if (v || v === 0) {
                        checkedKeys.value = v
                    } else {
                        checkedKeys.value = null
                    }
                }
                // checkInitData(datalist.value)
            },
            { immediate: true }
        )

        watch(
            () => props.data,
            (v) => {
                dataRef.value = deepClone(v)
                setTimeout(() => {
                    initData()
                }, 36)
            },
            { immediate: true, deep: true }
        )

        watch(
            () => props.filterValue,
            () => {
                filterData()
            }
        )

        return {
            datalist,
            unCheckedStatus,
            halfCheckedStatus,
            isCheckedStatus,
            handleCheckChange,
            handleRadioChange,
            handleLabelClick,
            handleExpandedChange,
            loadLoading,

            // updateChildrenByKey: () => {},
            // insertBeforeByKey: () => {},
            // insertAfterByKey: () => {},
            getCheckedKeys,
            setCheckedKeys,
            getHalfCheckedKeys,
            getUncheckedKeys,
            getExpandedKeys,
            getUnexpandedKeys,
            setExpandedKeys,
            getCheckedNodes,
            getHalfCheckedNodes,
            getUncheckedNodes,
            getExpandedNodes,
            getUnexpandedNodes
        }
    }
})
</script>

<style lang="scss" scoped>
@font-face {
    font-family: 'da-tree-iconfont'; /* Project id  */
    src: url('data:application/octet-stream;base64,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')
        format('truetype');
}

.da-tree {
    width: 100%;
    height: 100%;

    &-scroll {
        width: 100%;
        height: 100%;
    }

    &-item {
        display: flex;
        align-items: center;
        height: 0;
        padding: 0;
        overflow: hidden;
        font-size: 28rpx;
        line-height: 1.3;
        visibility: hidden;
        opacity: 0;
        transition: opacity 0.2s linear;

        &.is-show {
            height: auto;
            padding: 12rpx 24rpx;
            visibility: visible;
            opacity: 1;
        }

        &__icon {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 40rpx;
            height: 40rpx;
            overflow: hidden;

            &--arr {
                position: relative;
                display: flex;
                align-items: center;
                justify-content: center;
                width: 32rpx;
                height: 32rpx;

                &::after {
                    position: relative;
                    z-index: 1;
                    overflow: hidden;
                    /* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */
                    font-family: 'da-tree-iconfont' !important;
                    font-size: 32rpx;
                    font-style: normal;
                    color: #999;
                    -webkit-font-smoothing: antialiased;
                    -moz-osx-font-smoothing: grayscale;
                }

                &.is-expand {
                    &::after {
                        content: '\e604';
                    }
                }

                &.is-right {
                    transform: rotate(-90deg);
                }

                &.is-loading {
                    animation: IconLoading 1s linear 0s infinite;

                    &::after {
                        content: '\e7f1';
                    }
                }
            }
        }

        &__checkbox {
            width: 40rpx;
            height: 40rpx;
            overflow: hidden;

            &--left {
                order: 0;
            }

            &--right {
                order: 1;
            }

            &--icon {
                position: relative;
                display: flex;
                align-items: center;
                justify-content: center;
                width: 40rpx;
                height: 40rpx;

                &::after {
                    position: relative;
                    top: 0;
                    left: 0;
                    z-index: 1;
                    overflow: hidden;
                    /* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */
                    font-family: 'da-tree-iconfont' !important;
                    font-size: 32rpx;
                    font-style: normal;
                    -webkit-font-smoothing: antialiased;
                    -moz-osx-font-smoothing: grayscale;
                }

                &.da-tree-checkbox-outline::after {
                    color: #bbb;
                    content: '\ead5';
                }

                &.da-tree-checkbox-checked::after {
                    color: var(--theme-color, #007aff);
                    content: '\ead4';
                }

                &.da-tree-checkbox-indeterminate::after {
                    color: var(--theme-color, #007aff);
                    content: '\ebce';
                }

                &.da-tree-radio-outline::after {
                    color: #bbb;
                    content: '\ecc5';
                }

                &.da-tree-radio-checked::after {
                    color: var(--theme-color, #007aff);
                    content: '\ecc4';
                }

                &.da-tree-radio-indeterminate::after {
                    color: var(--theme-color, #007aff);
                    content: '\ea4f';
                }
            }

            &.is--disabled {
                cursor: not-allowed;
                opacity: 0.35;
            }
        }

        &__label {
            flex: 1;
            margin-left: 4rpx;
            color: #555;

            &--2 {
                color: var(--theme-color, #007aff);
            }

            &--append {
                font-size: 60%;
                opacity: 0.6;
            }
        }
    }
}

@keyframes IconLoading {
    0% {
        transform: rotate(0deg);
    }

    100% {
        transform: rotate(360deg);
    }
}
</style>
